home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Python 1.3.3 / Python 133 PPC / Demo / tkinter / guido / hanoi.py < prev    next >
Text File  |  1996-05-19  |  4KB  |  156 lines

  1. # Animated Towers of Hanoi using Tk with optional bitmap file in
  2. # background.
  3. #
  4. # Usage: tkhanoi [n [bitmapfile]]
  5. #
  6. # n is the number of pieces to animate; default is 4, maximum 15.
  7. #
  8. # The bitmap file can be any X11 bitmap file (look in
  9. # /usr/include/X11/bitmaps for samples); it is displayed as the
  10. # background of the animation.  Default is no bitmap.
  11.  
  12. # This uses Steen Lumholt's Tk interface
  13. from Tkinter import *
  14.  
  15.  
  16. # Basic Towers-of-Hanoi algorithm: move n pieces from a to b, using c
  17. # as temporary.  For each move, call report()
  18. def hanoi(n, a, b, c, report):
  19.     if n <= 0: return
  20.     hanoi(n-1, a, c, b, report)
  21.     report(n, a, b)
  22.     hanoi(n-1, c, b, a, report)
  23.  
  24.  
  25. # The graphical interface
  26. class Tkhanoi:
  27.  
  28.     # Create our objects
  29.     def __init__(self, n, bitmap = None):
  30.         self.n = n
  31.         self.tk = tk = Tk()
  32.         self.canvas = c = Canvas(tk)
  33.         c.pack()
  34.         width, height = tk.getint(c['width']), tk.getint(c['height'])
  35.  
  36.         # Add background bitmap
  37.         if bitmap:
  38.             self.bitmap = c.create_bitmap(width/2, height/2,
  39.                               {'bitmap': bitmap,
  40.                                'foreground': 'blue'})
  41.  
  42.         # Generate pegs
  43.         pegwidth = 10
  44.         pegheight = height/2
  45.         pegdist = width/3
  46.         x1, y1 = (pegdist-pegwidth)/2, height*1/3
  47.         x2, y2 = x1+pegwidth, y1+pegheight
  48.         self.pegs = []
  49.         p = c.create_rectangle(x1, y1, x2, y2, {'fill': 'black'})
  50.         self.pegs.append(p)
  51.         x1, x2 = x1+pegdist, x2+pegdist
  52.         p = c.create_rectangle(x1, y1, x2, y2, {'fill': 'black'})
  53.         self.pegs.append(p)
  54.         x1, x2 = x1+pegdist, x2+pegdist
  55.         p = c.create_rectangle(x1, y1, x2, y2, {'fill': 'black'})
  56.         self.pegs.append(p)
  57.         self.tk.update()
  58.  
  59.         # Generate pieces
  60.         pieceheight = pegheight/16
  61.         maxpiecewidth = pegdist*2/3
  62.         minpiecewidth = 2*pegwidth
  63.         self.pegstate = [[], [], []]
  64.         self.pieces = {}
  65.         x1, y1 = (pegdist-maxpiecewidth)/2, y2-pieceheight-2
  66.         x2, y2 = x1+maxpiecewidth, y1+pieceheight
  67.         dx = (maxpiecewidth-minpiecewidth) / (2*max(1, n-1))
  68.         for i in range(n, 0, -1):
  69.             p = c.create_rectangle(x1, y1, x2, y2,
  70.                            {'fill': 'red'})
  71.             self.pieces[i] = p
  72.             self.pegstate[0].append(i)
  73.             x1, x2 = x1 + dx, x2-dx
  74.             y1, y2 = y1 - pieceheight-2, y2-pieceheight-2
  75.             self.tk.update()
  76.             self.tk.after(25)
  77.  
  78.     # Run -- never returns
  79.     def run(self):
  80.         while 1:
  81.             hanoi(self.n, 0, 1, 2, self.report)
  82.             hanoi(self.n, 1, 2, 0, self.report)
  83.             hanoi(self.n, 2, 0, 1, self.report)
  84.             hanoi(self.n, 0, 2, 1, self.report)
  85.             hanoi(self.n, 2, 1, 0, self.report)
  86.             hanoi(self.n, 1, 0, 2, self.report)
  87.  
  88.     # Reporting callback for the actual hanoi function
  89.     def report(self, i, a, b):
  90.         if self.pegstate[a][-1] != i: raise RuntimeError # Assertion
  91.         del self.pegstate[a][-1]
  92.         p = self.pieces[i]
  93.         c = self.canvas
  94.  
  95.         # Lift the piece above peg a
  96.         ax1, ay1, ax2, ay2 = c.bbox(self.pegs[a])
  97.         while 1:
  98.             x1, y1, x2, y2 = c.bbox(p)
  99.             if y2 < ay1: break
  100.             c.move(p, 0, -1)
  101.             self.tk.update()
  102.  
  103.         # Move it towards peg b
  104.         bx1, by1, bx2, by2 = c.bbox(self.pegs[b])
  105.         newcenter = (bx1+bx2)/2
  106.         while 1:
  107.             x1, y1, x2, y2 = c.bbox(p)
  108.             center = (x1+x2)/2
  109.             if center == newcenter: break
  110.             if center > newcenter: c.move(p, -1, 0)
  111.             else: c.move(p, 1, 0)
  112.             self.tk.update()
  113.  
  114.         # Move it down on top of the previous piece
  115.         pieceheight = y2-y1-2
  116.         newbottom = by2 - pieceheight*len(self.pegstate[b]) - 2
  117.         while 1:
  118.             x1, y1, x2, y2 = c.bbox(p)
  119.             if y2 >= newbottom: break
  120.             c.move(p, 0, 1)
  121.             self.tk.update()
  122.  
  123.         # Update peg state
  124.         self.pegstate[b].append(i)
  125.  
  126.  
  127. # Main program
  128. def main():
  129.     import sys, string
  130.  
  131.     # First argument is number of pegs, default 4
  132.     if sys.argv[1:]:
  133.         n = string.atoi(sys.argv[1])
  134.     else:
  135.         n = 4
  136.  
  137.     # Second argument is bitmap file, default none
  138.     if sys.argv[2:]:
  139.         bitmap = sys.argv[2]
  140.         # Reverse meaning of leading '@' compared to Tk
  141.         if bitmap[0] == '@': bitmap = bitmap[1:]
  142.         else: bitmap = '@' + bitmap
  143.     else:
  144.         bitmap = None
  145.  
  146.     # Create the graphical objects...
  147.     h = Tkhanoi(n, bitmap)
  148.  
  149.     # ...and run!
  150.     h.run()
  151.  
  152.  
  153. # Call main when run as script
  154. if __name__ == '__main__':
  155.     main()
  156.